/* 
 * SharedMethods.java      1.00    2008-01-11
 *
 * Copyright (c) 2010 monolist. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information
 * of monolist.  You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the license agreement
 * you entered into with monolist.
 */
package doit.framework.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Clob;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.directwebremoting.WebContextFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.dao.DataAccessException;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

/**
 * <pre>
 * system      : 공통
 * menu        : 공통
 * source      : SharedMethods.java
 * description : 유틸
 * </pre> 
 * @version
 * <pre> 
 * 1.0  2008-01-11  monolist  최초 작성
 * 1.1  
 * </pre>
 */

@SuppressWarnings("unchecked")

public class SharedMethods {

    public static String[] fields = {   Config.getString( "doit.common.upd-col.creId"), 
                                        Config.getString( "doit.common.upd-col.creClass"),
                                        Config.getString( "doit.common.upd-col.creIp"),
                                        Config.getString( "doit.common.upd-col.updId"),
                                        Config.getString( "doit.common.upd-col.updClass"),
                                        Config.getString( "doit.common.upd-col.updIp")};
    
    /**
     * URL 인코딩
     * @param value
     * @return
     */
    public static String encodeURLString(String value) {
        if( value == null) return Constants.VL_EMPTY;
        
        String enocdeURL = value;

        enocdeURL = StringUtils.replace(enocdeURL, Constants.VL_HEX_25, Constants.VL_TRANS_HEX_25);
        enocdeURL = StringUtils.replace(enocdeURL, Constants.VL_HEX_26, Constants.VL_TRANS_HEX_26);
        enocdeURL = StringUtils.replace(enocdeURL, Constants.VL_HEX_2F, Constants.VL_TRANS_HEX_2F);
        enocdeURL = StringUtils.replace(enocdeURL, Constants.VL_HEX_3D, Constants.VL_TRANS_HEX_3D);
        enocdeURL = StringUtils.replace(enocdeURL, Constants.VL_HEX_3F, Constants.VL_TRANS_HEX_3F);
        enocdeURL = StringUtils.replace(enocdeURL, Constants.VL_HEX_0A, Constants.VL_TRANS_HEX_0A);

        return enocdeURL;
    }

    /**
     * 파라메터 add appendParameter :
     * @param url
     * @param key
     * @param value
     * @return
     */
    public static String appendParameter(String url, String key, String value) {
        StringBuffer sbResult = new StringBuffer(url);

        sbResult = appendParameter(sbResult, key, value);

        return sbResult.toString();
    }

    /**
     * 파라메터 add appendParameter :
     * @param url
     * @param key
     * @param value
     * @return
     */
    public static StringBuffer appendParameter(StringBuffer url, String key, String value) {
        if (key == null || key.length() <= 0) {
            return url;
        }
        if (value == null || value.length() <= 0) {
            return url;
        }

        String encodeURL = url.toString();
        String separator = Constants.VL_EMPTY;

        if (encodeURL.indexOf(Constants.VL_PARAMETER_START_PREFIX) == -1) {
            separator = Constants.VL_PARAMETER_START_PREFIX;
        } else if (!encodeURL.toString().endsWith(Constants.VL_PARAMETER_START_PREFIX) && !encodeURL.endsWith(Constants.VL_PARAMETER_ADD_PREFIX)) {
            separator = Constants.VL_PARAMETER_ADD_PREFIX;
        }

        // check 'key=' exists, then replace exist-value with input-value
        int index = encodeURL.indexOf(key + Constants.VL_PARAMETER_VALUE_PREFIX);
        if (index >= 0) {
            int nEndIndex = encodeURL.indexOf(Constants.VL_PARAMETER_ADD_PREFIX, index);
            if (nEndIndex < index) {
                nEndIndex = encodeURL.length();
            }

            url.replace(index, nEndIndex, key + Constants.VL_PARAMETER_VALUE_PREFIX + encodeURLString(value));
        } else {
            url.append(separator).append(key).append(Constants.VL_PARAMETER_VALUE_PREFIX).append( encodeURLString(value));
        }

        return url;
    }

    /**
     * 전달 받은 스트링이 null 및 공백문자열 인지를 체크 후 boolean 리턴
     * @param value
     * @return
     */
    public static boolean boundStringNull(String value) {
        boolean isNull = false;

        if ((value == null || value.trim().length() == 0))
            isNull = true;

        return isNull;
    }

    /**
     * String 문자열 val를 null체크 val값을 Constants.VL_EMPTY값으로 반환
     * @param value
     * @return
     */
    public static String nullCheck(String value) {
        if (value == null)
            return Constants.VL_EMPTY;
        else
            return value;
    }

    /**
     * String 문자열 val를 null체크 변환 val값을 val1으로 반환
     * @param value
     * @param convertValue
     * @return
     */
    public static String nullCheck(String value, String convertValue) {
        if (value == null || value.equals( Constants.VL_NULL))
            return convertValue;
        else
            return value;
    }

    /**
     * String 문자열 val를 null체크 int타입의 val1으로 반환
     * @param value
     * @param convertValue
     * @return
     */
    public static String nullCheck( String value, int convertValue) {
        if (value == null || value.length() <= 0)
            return convertValue + Constants.VL_EMPTY;
        else
            return value.toString();
    }

    /**
     * 널 체크
     * @param value
     * @return
     */
    public static String nullCheck(Object value) {
        if (value == null)
            return Constants.VL_EMPTY;
        else
            return value.toString();
    }

    /**
     * Date를 SimpleDateFormat으로 변형하여 날짜 스트링을 리턴한다.
     * @param date
     * @param dateFormat
     * @return
     */
    public static String getDate(Date date, String dateFormat) {
        SimpleDateFormat myDateFormat = new SimpleDateFormat(dateFormat);
        return myDateFormat.format(date);
    }

    /**
     * 현재 시간을 SimpleDateFormat으로 변형하여 날짜 스트링을 리턴한다.
     * @param dateFormat
     * @return
     */
    public static String getDate(String dateFormat) {
        return getDate( new Date(), dateFormat);
    }
    
    /**
     * 현재일을 기준으로 몇일 지난 날짜 스트링을 리턴한다.
     * @param dateFormat
     * @param day
     * @return
     */
    public static String getDDay(String dateFormat, int day) {
        SimpleDateFormat myDateFormat = new SimpleDateFormat(dateFormat);

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, day);
        return myDateFormat.format(calendar.getTime());
    }
    
    // 숫자 변환
    public static Number str2Number(String value) {
        return parseNumber(value, Constants.VL_NUMBER_PATTERN);
    }
    
    public static String num2String(int value){
        return formatNumber(value, Constants.VL_NUMBER_PATTERN);
    }
    
    public static String num2String(long value){
        return formatNumber(value, Constants.VL_NUMBER_PATTERN);
    }
    
    public static String num2String(double value){
        return formatNumber(value, Constants.VL_NUMBER_PATTERN);
    }
    
    public static String num2String(Number value){
        return formatNumber(value, Constants.VL_NUMBER_PATTERN);
    }

    private static final DecimalFormat df = new DecimalFormat();
    
    public static Number parseNumber(String value, String pattern) {
        Number ret = null;
        try{
            df.applyPattern(pattern);
            ret = df.parse(value, new ParsePosition(0));
        }catch(Exception ex){
            if (Constants.DEBUG_MODE){
                ex.printStackTrace();
            }
        }
        return ret;
    }
    
    public static String formatNumber(int value, String pattern) {
        df.applyPattern(pattern);
        return df.format(value);
    }
    
    public static String formatNumber(long value, String pattern) {
        df.applyPattern(pattern);
        return df.format(value);
    }
    
    public static String formatNumber(double value, String pattern) {
        df.applyPattern(pattern);
        return df.format(value);
    }
    
    public static String formatNumber(Number value, String pattern) {
        df.applyPattern(pattern);
        return df.format(value.doubleValue());
    }
    
    /**
     * 디렉토리 삭제
     * deleteDirectorys : 
     * @param parentDir
     * @param childDir
     * @return
     */
    public static boolean deleteDirectorys(String parentDir, String childDir) {
        boolean _result = true;
        try {
            File directory = new File(parentDir, childDir);
            deleteAllFile(directory);
        } catch (Exception e) {
            e.printStackTrace();
            _result = false;
        }
        return _result;
    }
    
    /**
     * 디렉토리 파일 삭제
     * deleteAllFile : 
     * @param file
     */
    public static void deleteAllFile(File file) {
        File[] fileList = file.listFiles();
        if (fileList != null && fileList.length != 0) {
            for (int i = 0; i < fileList.length; i++) {
                if (fileList[i].isDirectory()) {
                    deleteAllFile(fileList[i]);
                } else {
                    fileList[i].delete();
                }
            }
        }
        file.delete();
    }

    /**
     * 파일 생성
     * makeFile : 
     * @param fullFileName
     * @return
     */
    public static File makeFile(String fullFileName) {
        File genFile = null;
        try {
            genFile = new File(fullFileName);
            if (!genFile.exists()) {
                genFile.createNewFile();
            } else {
                genFile.delete();
                genFile.createNewFile();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return genFile;
    }
    
    /**
     * Byte 배열을 변환하여 Object로 반환한다.
     * @param bytes
     * @return
     * @throws Exception
     */
    public static Object byteToObject(byte[] bytes) throws Exception {
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream oip = new ObjectInputStream(bis);
        return oip.readObject();
    }
    
    /**
     * Object를 Byte 배열로 변환하여 리턴한다.
     * @param object
     * @return
     * @throws Exception
     */
    public static byte[] objectToByte(Object object) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        ObjectOutputStream oos = new ObjectOutputStream(baos); 
        oos.writeObject(object); 
        return baos.toByteArray(); 
    }
    
    /**
     * 
     * @param list
     * @param key : select value
     * @param text : select text
     * @return
     * @throws Exception
     */
    public static Map selectGenerate(List list, String key, String text) throws Exception {
        Map map = new HashMap();
        if (list.size() > 0) {
            for (Object obj : list) {
                Class clazz = obj.getClass();
                String getMethod = "get" + key.substring(0, 1).toUpperCase() +  key.substring(1);
                Method method = clazz.getMethod(getMethod);
                String keyTemp = String.valueOf(method.invoke(obj));
                
                getMethod = "get" + text.substring(0, 1).toUpperCase() +  text.substring(1);
                method = clazz.getMethod(getMethod);
                String textTemp = String.valueOf(method.invoke(obj));
                
                map.put(keyTemp, textTemp);
            }
        }
        
        return map;
    }

    /**
     * 일정한 길이만큼 좌측으로 문자를 채운다
     * @param value String
     * @param putChar char
     * @param count int
     * @return String
     */
    public static String lpad(String value, char putChar, int count){
        String valueStr = Constants.VL_EMPTY;
        if(value != null && value.length() < count){
            int srcCnt = value.length();
            int forCnt = count - srcCnt;
            String putString = Constants.VL_EMPTY;

            for(int i=0 ; i<forCnt ; i++){
                putString += String.valueOf(putChar);
            }
            valueStr = putString + value;
        } else {
            valueStr = value;
        }

        return valueStr;
    }

    /**
     * 일정한 길이만큼 우측으로 문자를 채운다
     * @param value String
     * @param putChar char
     * @param count int
     * @return String
     */
    public static String rpad(String value, char putChar, int count){
        String valueStr = Constants.VL_EMPTY;
        if(value != null && value.length() < count){
            int srcCnt = value.length();
            int forCnt = count - srcCnt;
            String putString = Constants.VL_EMPTY;

            for(int i=0 ; i<forCnt ; i++){
                putString += String.valueOf(putChar);
            }

            valueStr = value + putString;
        } else {
            valueStr = value;
        }

        return valueStr;
    }
    
    /**
     * 첨부파일 확장자를 가져온다.
     * @param fileName
     * @return
     */
    public static String getFileExt( String fileName) {
        String surfix;
        String rValue  = Constants.VL_EMPTY;
        int pointIndex = fileName.lastIndexOf('.');

        if (pointIndex == -1 || pointIndex == (fileName.length() - 1))
            surfix = Constants.VL_EMPTY;
        else
            surfix = fileName.substring(pointIndex + 1);

        rValue = surfix.toLowerCase();

        return rValue;
    }
    
    /**
     * 전체 클래스명에서 마지막 클래스명만 가져온다.
     * @param clazz
     * @return
     */
    public static String getClassName( Class clazz) {
        String className = Constants.VL_EMPTY;
        StringTokenizer st = new StringTokenizer(clazz.getName(), ".");
        while (st.hasMoreTokens()) {
            className = st.nextToken();
        }
        
        return className;
    }
    
    /**
     * 파일 사이즈 정보를 리턴한다.
     * @param value
     * @return
     */
    public static String getFileSize( long value)
    {
        String szResult = null;

        DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();

        if ( (1024 * 1024) < value ) {
            df.applyPattern(Constants.VL_MB_PATTERN);
            szResult = df.format( value /  (1024 * 1024) ) + Constants.VL_MB;
        }
        else {
            df.applyPattern(Constants.VL_KB_PATTERN);
            szResult = df.format( ( value + 999 ) / 1024 ) + Constants.VL_KB;
        }

        return szResult;
    }
    
    /**
     * Request 정보를 Map에 bind한다.
     * @param input
     * @throws Exception
     */
    public static void bind( Map input) throws Exception{
        bind( getRequest(), input);
    }

    /**
     * Request 정보를 Map 배열에 bind한다.
     * @param inputs
     * @throws Exception
     */
    public static void bind( Map[] inputs) throws Exception{
        for( int i=0; inputs!=null&&i<inputs.length; i++)
            bind( inputs[i]);
    }
    
    /**
     * Map의 정보를 Object에 bind한다.
     * @param input
     * @param obj
     * @throws Exception
     */
    public static void bind( Map input, Object obj) throws Exception{
        new WebDataBinder( obj).bind( new MutablePropertyValues( input));
        setUpdInfo( input, obj);
    }
    
    /**
     * Map의 정보를 Object에 bind한다.
     * 쿼리 결과가 null인 경우는 제외한다.
     * @param input
     * @param obj
     * @throws DataAccessException
     */
    public static void bindDAOObject( Map input, Object obj) throws DataAccessException{
        if (input == null)
            return;
        Map castInput = new HashMap();
        Set set = input.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
            String key = String.valueOf(iterator.next());
            Object objData = input.get(key);
   
            if (objData instanceof java.sql.Clob) {
                try {
                    castInput.put( key, clobToString((Clob)objData));
                } catch(Exception e) {e.printStackTrace();}
            } else {
                castInput.put( key, objData);
            }
        }
        new WebDataBinder( obj).bind( new MutablePropertyValues( castInput));
    }

    /**
     * Map의 정보를 Object에 bind한다.
     * 쿼리 결과가 null인 경우는 제외한다.
     * @param input
     * @param obj
     * @throws DataAccessException
     */
    public static void bindDAOObject( Map input) throws DataAccessException{
        if (input == null)
            return;
        Set set = input.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
            String key = String.valueOf(iterator.next());
            Object objData = input.get(key);
            
            if (objData instanceof java.sql.Clob) {
                try {
                    input.put(key, clobToString((Clob)objData));
                } catch(Exception e) {e.printStackTrace();}
            }
        }
    }

    
    /**
     * Map에 담겨있는 키를 조작하여 리턴한다.(ex. USER_ID -> userId)
     * @param input
     * @throws DataAccessException
     */
    public static void bindDAOObjectOnlyKey( Map input) throws DataAccessException{
        if (input == null)
            return;
        Map castInput = new HashMap();
        Set set = input.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
            String key = String.valueOf(iterator.next());
            Object objData = input.get(key);
            if (objData != null) {
                castInput.put(key, objData);
            } else {
                castInput.put(key, "");
            }
        }
        input.clear();
        input.putAll( castInput);
    }
    
    /**
     * List에 담겨있는 Map을 Object로 바꿔 리턴한다.
     * @param list
     * @param obj
     * @throws DataAccessException
     */
    public static void bindDAOObject(List list, Object obj) throws DataAccessException{
        if (list == null)
            return;
        List resultList = new ArrayList();
        try {
            for (int i = 0 ; i < list.size() ; i++) {
                Class c = obj.getClass().getClassLoader().loadClass(obj.getClass().getName());
                Object temp = c.newInstance();
                SharedMethods.bindDAOObject((Map)list.get(i), temp); 
                resultList.add(temp);
            }  
        } catch (Exception e) {
            e.printStackTrace();
        }
        list.clear();
        list.addAll(resultList);
    }

    /**
     * List에 담겨있는 Map을 Object로 바꿔 리턴한다.
     * @param list
     * @param obj
     * @throws DataAccessException
     */
    public static void bindDAOObject(List list) throws DataAccessException{
        if (list == null)
            return;
        try {
            for (int i = 0 ; i < list.size() ; i++) {
                SharedMethods.bindDAOObject((Map)list.get(i)); 
            }  
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * List에 담겨있는 Map을 키를 조작하여 리턴한다.(ex. USER_ID -> userId)
     * @param list
     * @throws DataAccessException
     */
    public static void bindDAOObjectOnlyKey(List list) throws DataAccessException{
        if (list == null)
            return;
        List resultList = new ArrayList();
        try {
            for (int i = 0 ; i < list.size() ; i++) {
                bindDAOObjectOnlyKey((Map)list.get(i));
                resultList.add(list.get(i));
            }  
        } catch (Exception e) {
            e.printStackTrace();
        }
        list.clear();
        list.addAll(resultList);
    }

    /**
     * Request 정보를 Map에 bind한다.
     * 단, Constants.PM_METHOD 값은 제외하고 Constants.PM_SYSTEM_DIV 값이 없는 경우 Constants.VL_PH로 설정한다.
     * @param request
     * @param input
     * @throws Exception
     */
    public static void bind(HttpServletRequest request, Map input) throws Exception {
        Enumeration e = request.getParameterNames();        
        while (e.hasMoreElements()) {
            String key = (String) e.nextElement();
            if (!request.getParameter(key).equals(Constants.VL_EMPTY) && request.getParameter(key) != null && !request.getParameter(key).equals(Constants.PM_METHOD)) {
                input.put( key, request.getParameter(key) );
            }
        }
        
        bindUpdInfo( request, input);
    }
    
    /**
     * Request 정보를 Object에 bind한다.
     * 단, Constants.PM_METHOD 값은 제외하고 Constants.PM_SYSTEM_DIV 값이 없는 경우 Constants.VL_PH로 설정한다.
     * @param request
     * @param object
     * @throws Exception
     */
    public static void bind(HttpServletRequest request, Object object) throws Exception {
        Map requestMap = new HashMap();
        Enumeration e = request.getParameterNames();        
        while (e.hasMoreElements()) {
            String key = (String) e.nextElement();
            if (!request.getParameter(key).equals(Constants.VL_EMPTY) && request.getParameter(key) != null && !request.getParameter(key).equals(Constants.PM_METHOD)) {
                requestMap.put( key, request.getParameter(key) );
            }
        }
        new WebDataBinder( object).bind( new MutablePropertyValues( requestMap));
        
        setUpdInfo( request, object);
    }
    
    /**
     * DWR용 Request를 가져온다.
     * @return
     */
    public static HttpServletRequest getRequest() {
        return WebContextFactory.get().getHttpServletRequest();
    }

    /**
     * DWR용 Reqsponse를 가져온다.
     * @return
     */
    public static HttpServletResponse getResponse() {
        return WebContextFactory.get().getHttpServletResponse();
    }

    /**
     * DWR용 Session를 가져온다.
     * @return
     */
    public static HttpSession getSession() {
        return WebContextFactory.get().getSession();
    }

    /**
     * Reqeust에서 Map에 등록/수정자 정보를 저장한다.
     * @param request
     * @param map
     * @throws Exception
     */
    public static void bindUpdInfo( HttpServletRequest request, Map map) throws Exception
    {
        if( request == null || map == null)
            return;
        
        for( int i=0; i<fields.length; i++)
            map.put( fields[i], request.getAttribute( fields[i]));
    }
    
    /**
     * Reqeust에서 Object에 등록/수정자 정보를 저장한다.
     * @param request
     * @param domain
     * @throws Exception
     */
    public static void setUpdInfo( HttpServletRequest request, Object domain) throws Exception
    {
        if( request == null || domain == null)
            return;
        
        for( int i=0; i<fields.length; i++)
            invokeMethod( domain, getSetMethodName( fields[i]), String.class, request.getAttribute( fields[i]));
    }
    
    /**
     * Map에서 Object에 등록/수정자 정보를 저장한다.
     * @param input
     * @param domain
     * @throws Exception
     */
    public static void setUpdInfo( Map input, Object domain) throws Exception
    {
        if( input == null || domain == null)
            return;
        
        for( int i=0; i<fields.length; i++)
            invokeMethod( domain, getSetMethodName( fields[i]), String.class, input.get( fields[i]));
    }
    
    /**
     * type이 다른 domain에서 Object에 등록/수정자 정보를 저장한다.
     * @param input
     * @param domain
     * @throws Exception
     */
    public static Object setUpdInfo( Object source, Object domain) throws Exception {
        if( source == null || domain == null)
            return null;
        
        String getMethodName = null;
        String setMethodName = null;
        Method getMethod = null;
        Method setMethod = null;
        for( int i=0; i < fields.length; i++) {
            getMethodName = getGetMethodName( fields[i]);
            setMethodName = getSetMethodName( fields[i]);
            
            getMethod = source.getClass().getMethod( getMethodName);
            setMethod = domain.getClass().getMethod( setMethodName, String.class);
            
            if( getMethod != null && setMethod != null) {
                setMethod.invoke( domain, getMethod.invoke(source));
            }
        }
        
        return domain;
    }
    
    /**
     * Map에서 Object 배열에 등록/수정자 정보를 저장한다.
     * @param input
     * @param domains
     * @throws Exception
     */
    public static void setUpdInfo( Map input, Object[] domains) throws Exception
    {
        if( input == null || domains == null)
            return;
        
        for( int i=0; i<domains.length; i++)
            setUpdInfo( input, domains[i]);     
    }
    
    /**
     * Class에서 MethodName의 Method가 존재하는지 여부
     * @param clazz
     * @param methodName
     * @return
     * @throws Exception
     */
    public static boolean validateMethod(Class clazz, String methodName) throws Exception {
        boolean isMethod = false;
        if (methodName != null && !methodName.equals(Constants.VL_EMPTY)) {
            Method[] methods = clazz.getMethods();
            for (Object method : methods) {
                if (((Method)method).getName().equals(methodName)) {
                    isMethod = true;
                    break;
                }
            }
        }
        
        return isMethod;
    }
    
    /**
     * 클래스 메소드를 실행한다.
     * @param object
     * @param methodName
     * @param parameterType
     * @param argument
     * @throws Exception
     */
    public static void invokeMethod(Object object, String methodName, Class parameterType, Object argument) throws Exception
    {
        Class[] parameterTypes = new Class[1];
        parameterTypes[0] = parameterType;
        
        Object[] arguments = new Object[1];
        arguments[0] = argument;
        
        invokeMethod( object, methodName, parameterTypes, arguments);
    }

    /**
     * 클래스 메소드를 실행한다.
     * @param object
     * @param methodName
     * @param parameterTypes
     * @param arguments
     * @throws Exception
     */
    public static void invokeMethod(Object object, String methodName, Class[] parameterTypes, Object[] arguments) throws Exception
    {
        if( object == null)
            return;
        
        if( methodName == null)
            return;
        
        try {
            Method method = object.getClass().getMethod( methodName, parameterTypes);
            
            if(method == null)
                return;
            
            method.invoke( object, arguments);
        }
        catch( NoSuchMethodException e) {
        }
    }
    
    /**
     * 도메인 클래스의 값을 복사하여 새로운 도메인 객체를 리턴한다.
     * @param obj
     * @return
     * @throws Exception
     */
    public static Object cloneDomain( Object obj) throws Exception {
        if( obj == null)
            return null;
        
        Class c = obj.getClass().getClassLoader().loadClass(obj.getClass().getName());
        Object newObj = c.newInstance();
        
        Field[] fields = c.getDeclaredFields();
        String getMethodName = null;
        String setMethodName = null;
        Method getMethod = null;
        Method setMethod = null;
        for( int i=0; i < fields.length; i++) {
            getMethodName = Constants.VL_GET + fields[i].getName().substring(0, 1).toUpperCase() + fields[i].getName().substring(1, fields[i].getName().length());
            setMethodName = Constants.VL_SET + fields[i].getName().substring(0, 1).toUpperCase() + fields[i].getName().substring(1, fields[i].getName().length());
            
            getMethod = obj.getClass().getMethod( getMethodName);
            if( fields[i].getType().toString().indexOf("String") > -1)
                setMethod = newObj.getClass().getMethod( setMethodName, String.class);
            else if( fields[i].getType().toString().indexOf("long") > -1)
                setMethod = newObj.getClass().getMethod( setMethodName, long.class);
            else if( fields[i].getType().toString().indexOf("int") > -1)
                setMethod = newObj.getClass().getMethod( setMethodName, int.class);
            
            if( getMethod != null && setMethod != null) {
                setMethod.invoke( newObj, getMethod.invoke(obj));
            }
        }
        
        return newObj;
    }
    
    /**
     * 데이터베이스 컬럼명에 대응하는 자바 필드명을 리턴한다.
     * @param columnName
     * @return
     */
    public static String getFieldName( String columnName) {
        if( columnName == null) return "";
        
        String[] arrFieldName = columnName.toLowerCase().split("_");
        
        String fieldName = "";
        for( int i=0; i < arrFieldName.length; i++) {
            if( i == 0)
                fieldName += arrFieldName[i];
            else
                fieldName += arrFieldName[i].substring(0, 1).toUpperCase() + arrFieldName[i].substring(1, arrFieldName[i].length());
        }
        
        return fieldName;
    }

    /**
     * 필드명에 대응하는 setMethod이름을 리턴한다.
     * @param fieldName
     * @return
     */
    public static String getSetMethodName( String fieldName) {
        if( fieldName == null) return "";
        
        return Constants.VL_SET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
    }

    /**
     * 필드명에 대응하는 getMethod이름을 리턴한다.
     * @param fieldName
     * @return
     */
    public static String getGetMethodName( String fieldName) {
        if( fieldName == null) return "";
        
        return Constants.VL_GET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
    }
    
    /**
     * 웹어플리케이션 컨텍스트를 가져온다.
     * @return
     */
    public static WebApplicationContext getContext() {
        return ContextLoader.getCurrentWebApplicationContext();
    }
    
    /**
     * beanName으로 웹어플리케이션 컨텍스트에 로드된 Bean을 가져온다.
     * @param beanName
     * @return
     */
    public static Object getWebApplicationBean( String beanName) {
        return getContext().getBean( beanName);
    }
    
    /**
     * 메세지를 가져온다.
     * @param messageKey 메세지 키
     * @param args 대체할 값 배열
     * @return
     */
    public static String getMessage( String messageKey, Object[] args) {
        if( messageKey == null || messageKey.length() <= 0)
            return null;
        
        ReloadableResourceBundleMessageSource bundle = new ReloadableResourceBundleMessageSource();
        bundle.setBasename( Constants.VL_MESSAGE_BASE_NAME);
        
        return bundle.getMessage( messageKey, args, Locale.getDefault());
    }
    
    
    public static String clobToString(Clob clob) throws SQLException, IOException {
        if (clob == null) {
            return "";
        }
        
        StringBuffer strOut = new StringBuffer();
        String str = "";
        BufferedReader br = new BufferedReader(clob.getCharacterStream());
        while ((str = br.readLine()) != null) {
            strOut.append(str);
        }
        return strOut.toString();
    } 
}
